/**
 * @title MyCalendarView.java
 * @package com.esun.cheetah.view.custom.calendar
 * @description 日历的主控件
 * @author liugan
 * @date 2012-4-14
 * @copyright 深圳市易讯天空
 */
package com.esun.cheetah.view.custom.calendar;

import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import com.esun.cheetah.R;
import com.esun.util.TimeUtil;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.NinePatch;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.MonthDisplayHelper;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.PopupWindow;
import android.widget.TextView;

/**
 * @title MyCalendarView
 * @description 日历控件
 * @author liugan
 */
public class CalendarView extends View {

	private static Format format = new SimpleDateFormat("yyyy-MM");

	/**
	 * @field mScale
	 * @description 单位为px的域（如日历的长、高等）根据密度不同需要放大或缩小的倍数
	 */
	private static float mScale = 0;

	private static final int WEEK_GAP = 0;// 行间隙
	private static final int MONTH_DAY_GAP = 0;// 列间隙

	/**
	 * @description 常量，标识某一天是属于当月，下月，还是上月
	 */
	public static final int CURRENT_MOUNTH = 0;
	public static final int NEXT_MOUNTH = 1;
	public static final int PREVIOUS_MOUNTH = -1;

	private boolean mMoveEventIsValid = false;

	/**
	 * 不同区域字体大小
	 */
	public static float WEEK_TEXT_SIZE = 12;
	public static float TITLE_TEXT_SIZE = 22;
	public static float DAY_TEXT_SIZE = 20;
	public static float HINT_TEXT_SIZE = 25;

	/**
	 * 顶部标题，星期高度为固定值
	 */
	public static int TOP_TITLE_HEIGHT = 34;
	public static int WEEK_HEIGHT = 26;

	/**
	 * 字符绘制位置的高度的偏移量
	 */

	public static int TEXT_HEIGHT_WEEK_OFFSET = 2;
	public static int TEXT_HEIGHT_TITLE_OFFSET = 5;
	public static int TEXT_HEIGHT_DAY_OFFSET = 3;
	public static int TEXT_HEIGHT_DAY_PRESSABLE_OFFSET = 4;
	public static int TEXT_HEIGHT_HINT_OFFSET = 4;

	/**
	 * 星期
	 */
	public static String weekTexts[] = { "日", "一", "二", "三", "四", "五", "六" };

	/**
	 * @description 推荐使用的日历尺寸，如果要改的话需确保宽高能被7整除（各个密度值下）
	 */
	private static int PROPER_WIDTH = 308;
	private static int PROPER_HEIGHT = 300;

	/**
	 * 绘制日历的工具
	 */
	private Canvas mCanvas;

	private Paint mTitlePaint;
	private Paint mWeekPaint;
	private Paint mGridPaint;
	private Paint mWhitePaint;
	private Paint mHintPaint;

	/**
	 * description 用到的图片资源
	 */
	private Bitmap mBufferBitmap;// 双缓冲底图
	private Bitmap mPreviousBitmapNormal;// 上月按钮
	private Bitmap mPreviousBitmapPressed;
	private Bitmap mNextBitmapNormal;// 下月按钮
	private Bitmap mNextBitmapPressed;
	private NinePatch mBackground9Patch;// 整个日历背景
	private NinePatch mTop9Patch;// 顶部标题背景
	private NinePatch mWeek9Patch;// 星期背景

	private String mHintText;// 用户按下了那一天

	private Calendar mCalendar;
	/**
	 * @field mCellHeight
	 * @description 日历格子高度
	 */
	private int mCellHeight;

	/**
	 * @field mCellWidth
	 * @description 日历格子宽度
	 */
	private int mCellWidth;

	private int cellTop;

	/**
	 * @field mBorder
	 * @description 日历边框的线条宽度
	 */
	private int mBorder;

	/**
	 * @description 日历中各个部分的矩形区域
	 */
	private Rect backgroundRect;// 整个背景
	private Rect topTitleRect;// 顶部标题
	private Rect topRect;// 顶部（包括按钮）
	private Rect weekRect;// 星期
	private Rect[] weekRects;// 星期日——星期一
	private Rect cellRect;// 整个月所有的格子所在区域
	private Rect previousRect, nextRect;// 上月、下月按钮
	private Rect previousBitmapRect, nextBitmapRect;// 上月、下月图标

	/**
	 * @field mCells
	 * @description 每一个Cell代表一天
	 */
	private Cell[][] mCells = new Cell[6][7];

	/**
	 * @field mOnCellTouchListener
	 * @description 点击事件监听器
	 */
	private OnCellTouchListener mOnCellTouchListener = null;

	private OnMonthChangeListener mOnMonthChangeListener = null;

	/**
	 * @field mHelper
	 * @description 用来获取日历所需数据的帮助类
	 */
	private MonthDisplayHelper mHelper;

	/**
	 * 上月下月按钮是否按下的标识
	 */
	private boolean previousHiting;
	private boolean nextHiting;

	/**
	 * @field
	 * @description 当用户按下时，如果落在某一个格子上，需要提示用户按下了那个日期
	 */

	private Context context;

	private PopupWindow window;

	private TextView popupText;

	private int mHintWidth;

	private int mHintHeight;

	/**
	 * 选择的Cell
	 */
	private Cell mSelectedCell;

	/**
	 * 已弹出提示框
	 */
	private boolean mPopupShowing;

	/**
	 * @param context
	 * @param attrs
	 */
	public CalendarView(Context context, AttributeSet attrs) {
		super(context, attrs);
		this.context = context;
		if (mScale == 0) {
			mScale = context.getResources().getDisplayMetrics().density;

			if (mScale != 1.0) {// 屏幕密度值不为1，则需要调整各个像素值

				PROPER_WIDTH *= mScale;
				PROPER_HEIGHT *= mScale;

				TEXT_HEIGHT_DAY_OFFSET *= mScale;
				TEXT_HEIGHT_WEEK_OFFSET *= mScale;
				TEXT_HEIGHT_TITLE_OFFSET *= mScale;
				TEXT_HEIGHT_HINT_OFFSET *= mScale;

				DAY_TEXT_SIZE *= mScale;
				WEEK_TEXT_SIZE *= mScale;
				TITLE_TEXT_SIZE *= mScale;
				HINT_TEXT_SIZE *= mScale;

				TOP_TITLE_HEIGHT *= mScale;
				WEEK_HEIGHT *= mScale;
			}

		}

		initSources();
	}

	/**
	 * @title initSources
	 * @description 部资源的初始化
	 */
	private void initSources() {
		mCalendar = TimeUtil.getInstance().getCalendar();
		mHelper = new MonthDisplayHelper(mCalendar.get(Calendar.YEAR),
				mCalendar.get(Calendar.MONTH), mCalendar.getFirstDayOfWeek());

		mTitlePaint = new Paint();
		mTitlePaint.setTextSize(TITLE_TEXT_SIZE);
		mTitlePaint.setAntiAlias(true);

		mWeekPaint = new Paint();
		mWeekPaint.setTextSize(WEEK_TEXT_SIZE);
		mWeekPaint.setAntiAlias(true);

		mGridPaint = new Paint();
		mGridPaint.setColor(Color.LTGRAY);
		mGridPaint.setAntiAlias(false);

		mWhitePaint = new Paint();
		mWhitePaint.setColor(Color.WHITE);

		mHintPaint = new Paint();
		mHintPaint.setAntiAlias(true);
		mHintPaint.setTextSize(HINT_TEXT_SIZE);

		// 触摸提示的view
		View ll = LayoutInflater.from(getContext()).inflate(
				R.layout.popup_window_hint, null);
		Resources resources = getResources();
		mHintWidth = (int) resources.getDimension(R.dimen.popup_width);
		mHintHeight = (int) resources.getDimension(R.dimen.popup_height);

		popupText = (TextView) ll.findViewById(R.id.popup_window_hint_text);
		window = new PopupWindow(ll, LayoutParams.WRAP_CONTENT,
				LayoutParams.WRAP_CONTENT);

	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		setMeasuredDimension(PROPER_WIDTH, PROPER_HEIGHT);// 将日历的大小设置为推荐的尺寸

	}

	@Override
	protected void onDraw(Canvas canvas) {
		if (mCanvas == null) {
			drawingCalc(getWidth(), getHeight());
		}

		if (mCanvas != null) {
			final Canvas bitmapCanvas = mCanvas;
			bitmapCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
			doDraw(bitmapCanvas);
		}

		if (mBufferBitmap != null) {
			canvas.drawBitmap(mBufferBitmap, backgroundRect, backgroundRect,
					mWhitePaint);
		}
	}

	/**
	 * @title doDraw
	 * @description 开始绘制
	 * @param bitmapCanvas
	 */
	private void doDraw(Canvas bitmapCanvas) {
		drawBackground(bitmapCanvas);
		drawTop(bitmapCanvas);
		drawTopTitle(bitmapCanvas);
		drawTopButton(bitmapCanvas);
		drawWeekTitle(bitmapCanvas);
		drawGrid(bitmapCanvas);
		drawCells(bitmapCanvas);
	}

	/**
	 * @title drawTop
	 * @description 绘制顶部标题
	 * @param bitmapCanvas
	 */
	private void drawTop(Canvas bitmapCanvas) {
		mTop9Patch.draw(bitmapCanvas, topRect);

	}

	/**
	 * @title drawTopButton
	 * @description 绘制顶部按钮
	 * @param bitmapCanvas
	 */
	private void drawTopButton(Canvas bitmapCanvas) {
		if (previousHiting) {
			bitmapCanvas.drawBitmap(mPreviousBitmapPressed, null,
					previousBitmapRect, null);
		} else {
			bitmapCanvas.drawBitmap(mPreviousBitmapNormal, null,
					previousBitmapRect, null);
		}

		if (nextHiting) {
			bitmapCanvas.drawBitmap(mNextBitmapPressed, null, nextBitmapRect,
					null);
		} else {
			bitmapCanvas.drawBitmap(mNextBitmapNormal, null, nextBitmapRect,
					null);
		}
	}

	/**
	 * @title drawWeekTitle
	 * @description 绘制星期文字
	 * @param bitmapCanvas
	 * @param mWeekPaint2
	 */
	private void drawWeekTitle(Canvas bitmapCanvas) {
		mWeek9Patch.draw(bitmapCanvas, weekRect);// 背景
		bitmapCanvas.drawLine(weekRects[0].left, weekRects[0].top,
				weekRects[6].right, weekRects[0].top, mGridPaint);

		float dx, dy;// 矩形中点到文字左下角的x、y距离
		for (int i = 0; i < 7; i++) {
			dx = (int) mWeekPaint.measureText(weekTexts[0]) / 2;
			dy = (int) (-mWeekPaint.ascent() + mWeekPaint.descent()) / 2;
			bitmapCanvas.drawText(weekTexts[i], weekRects[i].centerX() - dx,
					weekRects[i].centerY() + dy - TEXT_HEIGHT_WEEK_OFFSET,
					mWeekPaint);
		}

	}

	/**
	 * @title drawTopTitle
	 * @description 顶部的日期文字
	 * @param bitmapCanvas
	 * @param mTitlePaint2
	 */
	private void drawTopTitle(Canvas bitmapCanvas) {
		float dx, dy;// 矩形中点到文字左下角的x、y距离
		String dateString = format.format(mCalendar.getTime());
		dx = (int) mTitlePaint.measureText(dateString) / 2;
		dy = (int) (-mTitlePaint.ascent() + mTitlePaint.descent()) / 2;
		bitmapCanvas.drawText(dateString, topTitleRect.centerX() - dx,
				topTitleRect.centerY() + dy - TEXT_HEIGHT_TITLE_OFFSET,
				mTitlePaint);

	}

	/**
	 * @title drawCells
	 * @description 绘制日历的格子
	 * @param bitmapCanvas
	 */
	private void drawCells(Canvas bitmapCanvas) {
		for (Cell[] row : mCells) {
			for (Cell cell : row) {
				cell.draw(bitmapCanvas);
			}
		}

	}

	/**
	 * @title drawBackground
	 * @description 绘制背景
	 * @param bitmapCanvas
	 * @param p
	 */
	private void drawBackground(Canvas canvas) {
		mBackground9Patch.draw(canvas, backgroundRect);

	}

	/**
	 * @title drawGrid
	 * @description 绘制网格线
	 * @param bitmapCanvas
	 * @param p
	 */
	private void drawGrid(Canvas canvas) {

		final int width = getMeasuredWidth();
		final int height = getMeasuredHeight();

		for (int row = 0; row < 6; row++) {
			int y = cellTop + WEEK_GAP + row * (WEEK_GAP + mCellHeight) - 1;
			canvas.drawLine(0, y, width, y, mGridPaint);
		}
		for (int column = 1; column < 7; column++) {
			int x = mBorder + column * (MONTH_DAY_GAP + mCellWidth) - 1;
			canvas.drawLine(x, cellTop + WEEK_GAP, x, height, mGridPaint);
		}
	}

	/**
	 * @title drawingCalc
	 * @description 计算各位置以及图片资源的初始化
	 * @param width
	 * @param height
	 */
	private void drawingCalc(int width, int height) {

		mCellHeight = (height - TOP_TITLE_HEIGHT - WEEK_HEIGHT - (6 * WEEK_GAP)) / 6;
		mCellWidth = (width - (6 * MONTH_DAY_GAP)) / 7;
		cellTop = TOP_TITLE_HEIGHT + WEEK_HEIGHT;
		mBorder = (width - 6 * (mCellWidth + MONTH_DAY_GAP) - mCellWidth) / 2;

		if (((mBufferBitmap == null) || mBufferBitmap.isRecycled()
				|| (mBufferBitmap.getHeight() != height) || (mBufferBitmap
				.getWidth() != width)) && (width > 0) && (height > 0)) {
			if (mBufferBitmap != null) {
				mBufferBitmap.recycle();
			}

			mBufferBitmap = Bitmap.createBitmap(width, height,
					Bitmap.Config.ARGB_8888);
			mCanvas = new Canvas(mBufferBitmap);
			Bitmap backgroundBitmap = BitmapFactory.decodeResource(
					getResources(), R.drawable.bg_default_content);
			mBackground9Patch = new NinePatch(backgroundBitmap,
					backgroundBitmap.getNinePatchChunk(), null);

			Bitmap weekBitmap = BitmapFactory.decodeResource(getResources(),
					R.drawable.bg_default_week);
			mWeek9Patch = new NinePatch(weekBitmap,
					weekBitmap.getNinePatchChunk(), null);

			Bitmap titleBitmap = BitmapFactory.decodeResource(getResources(),
					R.drawable.bg_default_green);
			mTop9Patch = new NinePatch(titleBitmap,
					titleBitmap.getNinePatchChunk(), null);

			mNextBitmapNormal = BitmapFactory.decodeResource(getResources(),
					R.drawable.btn_default_triangle);
			mNextBitmapPressed = BitmapFactory.decodeResource(getResources(),
					R.drawable.btn_pressed_triangle);

			Matrix mMatrix = new Matrix();
			mMatrix.setRotate(180);
			mPreviousBitmapNormal = Bitmap.createBitmap(mNextBitmapNormal, 0,
					0, mNextBitmapNormal.getWidth(),
					mNextBitmapNormal.getHeight(), mMatrix, true);
			mPreviousBitmapPressed = Bitmap.createBitmap(mNextBitmapPressed, 0,
					0, mNextBitmapPressed.getWidth(),
					mNextBitmapPressed.getHeight(), mMatrix, true);
		}
		backgroundRect = new Rect();
		backgroundRect.top = 0;
		backgroundRect.bottom = height;
		backgroundRect.left = 0;
		backgroundRect.right = width;

		previousRect = new Rect();
		previousRect.top = 0;
		previousRect.bottom = TOP_TITLE_HEIGHT;
		previousRect.left = 0;
		previousRect.right = mCellWidth;

		previousBitmapRect = new Rect();
		previousBitmapRect.top = previousRect.centerY()
				- mPreviousBitmapNormal.getHeight() / 2;
		previousBitmapRect.bottom = previousBitmapRect.top
				+ mPreviousBitmapNormal.getHeight();
		previousBitmapRect.left = previousRect.centerX()
				- mPreviousBitmapNormal.getWidth() / 2;
		previousBitmapRect.right = previousBitmapRect.left
				+ mPreviousBitmapNormal.getWidth();

		nextRect = new Rect();
		nextRect.top = 0;
		nextRect.bottom = TOP_TITLE_HEIGHT;
		nextRect.left = width - mCellWidth;
		nextRect.right = width;

		nextBitmapRect = new Rect();
		nextBitmapRect.top = nextRect.centerY() - mNextBitmapNormal.getHeight()
				/ 2;
		nextBitmapRect.bottom = nextBitmapRect.top
				+ mNextBitmapNormal.getHeight();
		nextBitmapRect.left = nextRect.centerX() - mNextBitmapNormal.getWidth()
				/ 2;
		nextBitmapRect.right = nextBitmapRect.left
				+ mNextBitmapNormal.getWidth();

		topRect = new Rect();
		topRect.top = 0;
		topRect.bottom = TOP_TITLE_HEIGHT;
		topRect.left = 0;
		topRect.right = width;

		topTitleRect = new Rect();
		topTitleRect.top = 0;
		topTitleRect.bottom = TOP_TITLE_HEIGHT;
		topTitleRect.left = previousRect.right;
		topTitleRect.right = nextRect.left;

		weekRects = new Rect[7];
		for (int i = 0; i < 7; i++) {
			weekRects[i] = new Rect();
			weekRects[i].top = TOP_TITLE_HEIGHT;
			weekRects[i].bottom = weekRects[i].top + WEEK_HEIGHT;
			if (i == 0) {
				weekRects[i].left = 0;
			} else {
				weekRects[i].left = weekRects[i - 1].right;
			}
			weekRects[i].right = weekRects[i].left + mCellWidth + MONTH_DAY_GAP;

		}

		weekRect = new Rect();
		weekRect.top = weekRects[0].top + 1;
		weekRect.bottom = weekRects[0].bottom;
		weekRect.left = 0;
		weekRect.right = width;

		cellRect = new Rect();
		cellRect.top = cellTop;
		cellRect.bottom = height;
		cellRect.left = 0;
		cellRect.right = width;
		initCells();

	}

	/**
	 * @title initCells
	 * @description 初始化每个格子
	 */
	private void initCells() {
		mMoveEventIsValid = false;
		PreCell tmp[][] = new PreCell[6][7];

		// 构造PreCell数组
		for (int i = 0; i < tmp.length; i++) {
			int n[] = mHelper.getDigitsForRow(i);
			for (int d = 0; d < n.length; d++) {
				if (mHelper.isWithinCurrentMonth(i, d))
					tmp[i][d] = new PreCell(n[d], CURRENT_MOUNTH);
				else if (i == 0) {
					tmp[i][d] = new PreCell(n[d]);
				} else {
					tmp[i][d] = new PreCell(n[d], NEXT_MOUNTH);
				}

			}
		}

		Calendar today = TimeUtil.getInstance().getCalendar();
		int thisDay = 0;
		// 如果是当月，则需将thisDay赋值
		if (mHelper.getYear() == today.get(Calendar.YEAR)
				&& mHelper.getMonth() == today.get(Calendar.MONTH)) {
			thisDay = today.get(Calendar.DAY_OF_MONTH);
		}
		// 利用PreCell数组 构造Cell数组
		Rect Bound = new Rect(0, cellTop, mCellWidth, mCellHeight + cellTop);
		for (int week = 0; week < mCells.length; week++) {
			for (int day = 0; day < mCells[week].length; day++) {

				if (tmp[week][day].whichMonth == CURRENT_MOUNTH) { // 当前月份的日子
					// 判断是否是今天
					if (tmp[week][day].day == thisDay
							&& tmp[week][day].whichMonth == CURRENT_MOUNTH) {
						mCells[week][day] = new TodayCell(context,
								tmp[week][day].day, new Rect(Bound));
					} else {
						mCells[week][day] = new ThisMonthCell(context,
								tmp[week][day].day, new Rect(Bound));
					}
					mCells[week][day].setCurrentMonth(true);
				} else if (tmp[week][day].whichMonth == PREVIOUS_MOUNTH) {// 上月
					mCells[week][day] = new PreviousMonthCell(context,
							tmp[week][day].day, new Rect(Bound));
					mCells[week][day].setCurrentMonth(false);
				} else {
					mCells[week][day] = new NextMonthCell(context,
							tmp[week][day].day, new Rect(Bound));
					mCells[week][day].setCurrentMonth(false);
				}

				// 格子向后移动一位
				Bound.offset(mCellWidth, 0);

			}
			// 格子向下移动一行
			Bound.offset(0, mCellHeight); // move to next row and first column
			Bound.left = 0;
			Bound.right = mCellWidth;
		}

	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {

		case MotionEvent.ACTION_DOWN:
			this.mMoveEventIsValid = true;
			if (previousRect!=null&&previousRect.contains((int) event.getX(), (int) event.getY())) {// 上一月按下
				previousHiting = true;
				invalidate();

			} else if (nextRect
					.contains((int) event.getX(), (int) event.getY())) {// 下一月按下
				nextHiting = true;
				invalidate();
			} else if (cellRect
					.contains((int) event.getX(), (int) event.getY())) {

				for (Cell[] week : mCells) {// 每一行
					for (Cell day : week) {// 没一列
						if (day.hitTest((int) event.getX(), (int) event.getY())) {// 点击事件在一个格子里
							if (day.isCurrentMonth()) {
								day.setPressed(true);
								mSelectedCell = day;
								int location[] = new int[2];
								this.getLocationInWindow(location);
								int x = location[0] + day.mBound.centerX()
										- mHintWidth / 2;
								int y = location[1] + day.mBound.top
										- mHintHeight;
								mHintText = String.valueOf(day.getDayOfMonth());
								invalidate();
								showPopupWindow(mHintText, x, y);
								mPopupShowing = true;
							} else {
								if (day instanceof NextMonthCell) {
									this.nextMonth();
								} else if (day instanceof PreviousMonthCell) {
									this.previousMonth();
								}
							}

						} else {// 没点中的格子清除状态
							day.setPressed(false);
						}
					}
				}
			}
			break;
		case MotionEvent.ACTION_UP:

			if(mPopupShowing){
				dismissPopupWindow();
			}
			
			if (previousRect.contains((int) event.getX(), (int) event.getY())) {//

				if (previousHiting) {// 按下和离开都在改按钮内则激发相应事件，下同
					this.previousMonth();
				}

			} else if (nextRect
					.contains((int) event.getX(), (int) event.getY())) {

				if (nextHiting) {
					this.nextMonth();
				}

			} else if (cellRect
					.contains((int) event.getX(), (int) event.getY())) {
				for (Cell[] week : mCells) {// 每一行
					for (final Cell day : week) {// 每一列

						if (day.hitTest((int) event.getX(), (int) event.getY())
								&& day.isCurrentMonth()) {// 点在格子内
							if (day.isPressed()) {// 若已为选择状态，则产生点击事件
								day.setPressed(false);
								
								invalidate();
								if (mOnCellTouchListener != null) {
									new Handler().post(new Runnable(){
										public void run(){
											mOnCellTouchListener.onTouch(
													mCalendar.get(Calendar.YEAR),
													mCalendar.get(Calendar.MONTH),
													day.getDayOfMonth());
										}
									});
								
								}
							}
						} else {
							day.setPressed(false);
						}

					}
				}
			}
			nextHiting = false;
			previousHiting = false;

			invalidate();
			break;

		case MotionEvent.ACTION_MOVE:// 手指移动时，可选状态跟着改变
			if (this.mMoveEventIsValid) {
				if (cellRect.contains((int) event.getX(), (int) event.getY())) {
					for (Cell[] week : mCells) {
						for (Cell day : week) {
							// 移动到某个格子内则设置为可选状态
							if (day.hitTest((int) event.getX(),
									(int) event.getY())
									&& day.isCurrentMonth()) {
								day.setPressed(true);
								mSelectedCell = day;
								int location[] = new int[2];
								this.getLocationInWindow(location);
								int x = location[0] + day.mBound.centerX()
										- mHintWidth / 2;
								int y = location[1] + day.mBound.top
										- mHintHeight;
								mHintText = String.valueOf(day.getDayOfMonth());
								invalidate();
								showPopupWindow(mHintText, x, y);
								mPopupShowing = true;

							} else {
								if (day.isPressed()) {
									day.setPressed(false);
									invalidate();
									dismissPopupWindow();
								}

							}
						}
					}
				} else {
					if (mSelectedCell != null) {
						mSelectedCell.setPressed(false);
						mSelectedCell = null;
						invalidate();
					}
					if (mPopupShowing) {
						dismissPopupWindow();
						mPopupShowing = false;
					}
				}
			}

			break;

		case MotionEvent.ACTION_CANCEL:
		case MotionEvent.ACTION_OUTSIDE:
			for (Cell[] week : mCells) {
				for (Cell day : week) {
					day.setPressed(false);
				}
			}
			invalidate();
			break;

		}

		return true;
	}

	/**
	 * @title dismissPopupWindow
	 * @description
	 */
	private void dismissPopupWindow() {
		window.dismiss();

	}

	/**
	 * @title nextMonth
	 * @description 更换到下月
	 */
	public void nextMonth() {
		mHelper.nextMonth();
		mCalendar.add(Calendar.MONTH, 1);
		initCells();
		invalidate();
		monthChanged();

	}

	/**
	 * @title previousMonth
	 * @description 更换到前一月
	 */
	public void previousMonth() {
		mHelper.previousMonth();
		mCalendar.add(Calendar.MONTH, -1);
		initCells();
		invalidate();
		monthChanged();

	}

	/**
	 * @title goToday
	 * @description 跳转到当月
	 */
	public void goToday() {
		mCalendar = TimeUtil.getInstance().getCalendar();
		mHelper = new MonthDisplayHelper(mCalendar.get(Calendar.YEAR),
				mCalendar.get(Calendar.MONTH));
		initCells();
		invalidate();
		monthChanged();
	}

	public void setOnMonthChangeListener(
			OnMonthChangeListener onMonthChangeListener) {
		this.mOnMonthChangeListener = onMonthChangeListener;
	}

	private void monthChanged() {
		if (mOnMonthChangeListener != null) {
			mOnMonthChangeListener.onMonthChange(mCalendar.get(Calendar.YEAR),
					mCalendar.get(Calendar.MONTH));
		}
	}

	public void setOnCellTouchListener(OnCellTouchListener listener) {
		mOnCellTouchListener = listener;
	}

	public void showPopupWindow(String hintText, int x, int y) {

		popupText.setText(hintText);

		window.showAtLocation(this, Gravity.LEFT | Gravity.TOP, x, y);

	}

	/**
	 * @title PreCell
	 * @description 帮助完成日历格子的初始化的中间类
	 * @author liugan
	 */
	class PreCell {
		public int day;
		public int whichMonth; // -1 为上月 1为下月 0为此月

		public PreCell(int d, int b) {
			day = d;
			whichMonth = b;
		}

		public PreCell(int d) { // 上个月 默认为
			this(d, PREVIOUS_MOUNTH);
		}
	}

	/**
	 * @title OnCellTouchListener
	 * @description 点击事件监听器
	 * @author liugan
	 */
	public interface OnCellTouchListener {
		public void onTouch(int year, int month, int day);
	}

	public interface OnMonthChangeListener {
		/** month参数未加一，如不是用来比较使用需自行在原值上加一才是正确的月份 */
		void onMonthChange(int year, int month);
	}
}